﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SIEGate.Core;
using SIEGate.Core.Configurator;

namespace SIEGateCoreTest.ConfigTests
{
    [TestClass]
    public class GraphTests
    {
        ConfigGraph configGraph;
        Guid n1a, n1b, a1a, a2a, a3a;
        IDataProcessorInfo N1, N2;
        IAdapterInfo A1, A2, A3;


        [TestInitialize]
        public void TestsInitialize()
        {
            this.configGraph = new ConfigGraph();
        }

        private void buildSimpleGraph()
        {
            /*
             * This graph:
             *              ---n1a--> A1 ---a1a--------------
             * N1 -n1a, n1b-|                                | - a1a, a3a -> N2
             *               -- both -> A2 --a2a--> A3 - a3a--
             */
            /* Should bcome this collapse:
             *  N1, AC(A1), AC(A2, A3), N2
             */


            n1a = Guid.NewGuid();
            n1b = Guid.NewGuid();
            a1a = Guid.NewGuid();
            a2a = Guid.NewGuid();
            a3a = Guid.NewGuid();

            N1 = new MockDataProcessorInfo(new HashSet<Guid>(), new HashSet<Guid>() { n1a, n1b });
            N2 = new MockDataProcessorInfo(new HashSet<Guid>() { a1a, a3a }, new HashSet<Guid>());

            A1 = new MockAdapter.MockAdapterInfo(new HashSet<Guid>() { n1a }, new HashSet<Guid>() { a1a });
            A2 = new MockAdapter.MockAdapterInfo(new HashSet<Guid>() { n1a, n1b }, new HashSet<Guid>() { a2a });
            A3 = new MockAdapter.MockAdapterInfo(new HashSet<Guid>() { a2a }, new HashSet<Guid>() { a3a });

            N1.ID = 1;
            N2.ID = 2;
            A1.ID = 3;
            A2.ID = 4;
            A3.ID = 5;

            List<IConfigInfo> baseConfigs = new List<IConfigInfo>() { N1, N2, A1, A2, A3 };
            configGraph.Build(baseConfigs);
        }

        [TestMethod]
        public void SimpleCollapseCase()
        {
            buildSimpleGraph();
            configGraph.Collapse();


            List<IDataProcessorInfo> postCollapse = new List<IDataProcessorInfo>(configGraph.Nodes);
            Assert.AreEqual(true, postCollapse.Contains(N1));
            Assert.AreEqual(true, postCollapse.Contains(N2));

            Dictionary<string, int> res = new Dictionary<string, int>() {
                {"N1", 0},
                {"N2", 0},
                {"AC(A1)", 0},
                {"AC(A2,A3)", 0},
                {"other", 0},
            };

            foreach (IDataProcessorInfo node in postCollapse)
            {
                IAdapterContainerInfo ac = node as IAdapterContainerInfo;
                if ((object)ac == null)
                {
                    if (node == N1)
                    {
                        res["N1"]++;
                    }
                    if (node == N2)
                    {
                        res["N2"]++;
                    }
                }
                else if (ac.MemberInfos.Contains(A1))
                {
                    if (!(ac.MemberInfos.Count == 1))
                    {
                        throw new Exception("Container with A1 has more than 1 info!");
                    }
                    else
                    {
                        res["AC(A1)"]++;
                    }
                }
                else if (ac.MemberInfos.Contains(A2) || ac.MemberInfos.Contains(A3))
                {
                    if (ac.MemberInfos.Count > 2)
                    {
                        throw new Exception("Container with A2 or A3 has too many infos");
                    }
                    else if (ac.MemberInfos.Count < 2)
                    {
                        throw new Exception("Container with A2 or A3 has too few infos");
                    }

                    if (!ac.MemberInfos.Contains(A2))
                    {
                        throw new Exception("Container should have A2 and A3, missing A2 (but has something else)");
                    }
                    if (!ac.MemberInfos.Contains(A3))
                    {
                        throw new Exception("Container should have A2 and A3, missing A3 (but has something else)");
                    }
                    res["AC(A2,A3)"]++;
                }
                else
                {
                    res["other"]++;
                }
            }

            if (res["other"] != 0)
            {
                throw new Exception("There was somethig in 'other!'");
            }
            res.Remove("other");
            foreach (KeyValuePair<string, int> i in res)
            {
                if (i.Value != 1)
                {
                    throw new Exception(string.Format("Bad count for: {0} --> {1}", i.Key, i.Value));
                }
            }
        }

        [TestMethod]
        public void TestGetProviderFor()
        {
            buildSimpleGraph();
            configGraph.Collapse();
            uint providerID;
            if (!(ConfigGraph.GetProviderFor(a3a, out providerID)))
            {
                throw new Exception("GetProviderFor gave a false negative!");
            }
            Assert.AreEqual(A3.ID, providerID);
            if (ConfigGraph.GetProviderFor(Guid.NewGuid(), out providerID))
            {
                throw new Exception("GetProviderFor gave a false positive!");
            }
        }
    }
}
